#include "ConstSmallFileProxy.h"
#include "wrap/stat.h"
#include "wrap/unistd.h"

#include <sys/stat.h>

namespace _ {

static bool is_file(int fd, struct ::stat &statbuf) {
    return Wrap::fstat_(fd, &statbuf) == 0 && S_ISREG(statbuf.st_mode);
}

}

ConstSmallFileProxy::~ConstSmallFileProxy() = default;

BufferConstSmallFileProxy::BufferConstSmallFileProxy(int fd):
    ConstSmallFileProxy{}, _buffer{}, _fd{fd} {}

BufferConstSmallFileProxy::~BufferConstSmallFileProxy() = default;

std::uintmax_t BufferConstSmallFileProxy::file_size() const {
    struct ::stat statbuf {};
    return _::is_file(_fd, statbuf)
                ? static_cast<std::uintmax_t>(statbuf.st_size)
                : 0;
}

ssize_t BufferConstSmallFileProxy::read() {
    const auto result = 
        Wrap::pread_(_fd, _buffer.data(), _buffer.size() - 1, 0);
    if (result >= 0) {
        _buffer.at(static_cast<std::size_t>(result)) = '\0';
    }
    return result;
}

std::string BufferConstSmallFileProxy::read_no_more_than(std::size_t maxSize) {
    struct ::stat statbuf {};
    std::string result{};
    if (_::is_file(_fd, statbuf)) {
        result.reserve(
            std::min(maxSize, static_cast<std::size_t>(statbuf.st_size)));
    }
    while (result.size() < maxSize) {
        const auto n = Wrap::read_(
            _fd, _buffer.data(), 
            std::min(maxSize - result.size(), _buffer.size()));
        result.append(_buffer.data(), static_cast<std::size_t>(n));
    }
    return result;
}

